namespace hjc {

	export class MoveSystem extends System {

		protected $concerns = [Velocity, Destin];
		protected execute(entities: Entity[], param: TimeParam): void {
			entities.forEach(entity => {
				if (entity.velocity.checkPfc() && !!entity.destin.enabled) {
					let tgt = entity.destin.target;
					if (numeric(tgt)) this._toDirection(entity);
					else if (tgt instanceof Position) this._toPosition(entity);
					else if (tgt instanceof AStarNode) this._toAStarNode(entity);
					else if (tgt instanceof Entity) this._followEntity(entity);
				}
			});
		}

		private _toDirection(entity: Entity): void {
			this._updatePos(entity, entity.destin.target as angle);
		}

		private _toPosition(entity: Entity): void {
			let [from, to] = [entity.position, entity.destin.target as Position];
			if (entity.velocity.speed >= entity.distTo(to.x, to.y)) {
				from.x = to.x; from.y = to.y;
				entity.destin.target = null;
			} else this._updatePos(entity, utils.angleOfPoints(from.x, from.y, to.x, to.y));
		}

		private _toAStarNode(entity: Entity): void {
			let [from, node] = [entity.position, entity.destin.target as AStarNode];
			if (entity.velocity.speed >= entity.distTo(node.x, node.y)) {
				from.x = node.x; from.y = node.y;
				entity.destin.target = null;
				let astar = entity.astar;
				if (!!astar) {
					let next = astar.nodes.head();
					if (!!next) {
						astar.dir8 = utils.angleToDir8(utils.angleOfPoints(entity.position.x, entity.position.y, next.x, next.y));
						astar.flag = next.flag;
					} else entity.doFunc(Func.Entity.onArrived, node);
				}
			} else this._updatePos(entity, utils.angleOfPoints(from.x, from.y, node.x, node.y));
		}

		private _followEntity(entity: Entity): void {
			let [from, to] = [entity.position, (entity.destin.target as Entity).position];
			if (entity.velocity.speed >= entity.distTo(to.x, to.y)) {
				from.x = to.x; from.y = to.y;
			} else this._updatePos(entity, utils.angleOfPoints(from.x, from.y, to.x, to.y))
		}

		private _updatePos(entity: Entity, angle: angle): void {
			entity.velocity.angle = angle;
			let [vx, vy] = entity.velocity.vct2;
			entity.position.x += vx;
			entity.position.y += vy;
		}
	}
}